package com.yu1996.gulimall.search.thread;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadTest {

  public static ExecutorService executors = Executors.newFixedThreadPool(10); // 定义全局的线程池（四种线程池类型）

  //  public static void main(String[] args) {
  //    //
  //    List<Student> students =
  //        Arrays.asList(
  //            new Student("张三", "一班", 23, 68D),
  //            new Student("李四", "二班", 22, 78D),
  //            new Student("王五", "一班", 21, 99D));
  //    //    System.out.println(students);
  //
  //    Map<String, List<Student>> collect =
  //        students.stream().collect(Collectors.groupingBy(Student::getClassname));
  //
  //    Map<String, List<String>> ress = new HashMap<>();
  //    List<String> studentsName = new ArrayList<>();
  //    for (String s : collect.keySet()) {
  //      List<Student> students1 = collect.get(s);
  //      for (Student student : students1) {
  //        studentsName.add(student.getName());
  //      }
  //      ress.put(s, studentsName);
  //    }
  //    System.out.println(JSON.toJSON(ress));
  //  }

  //  @Data
  //  @NoArgsConstructor
  //  @AllArgsConstructor
  //  static class Student {
  //    private String name;
  //    private String classname;
  //    private Integer age;
  //    private Double score;
  //  }

  public static void main(String[] args) throws ExecutionException, InterruptedException {
    //
    SimpleDateFormat format = new SimpleDateFormat("yyyy 年 MM 月 dd 日 E HH 点 mm 分 ss 秒");
    System.out.println("线程开始运行------------------" + format.format(new Date()));
    //    CompletableFuture<Void> runAsync =
    //        CompletableFuture.runAsync( // CompletableFuture.runAsync无入参无返回值
    //            () -> {
    //              System.out.println("当前线程" + Thread.currentThread().getId());
    //              int i = 10 / 2;
    //              System.out.println("运行结果是" + i);
    //            },
    //            executors);

    //    CompletableFuture<Integer> supplyAsync =
    //        CompletableFuture.supplyAsync( // 使用CompletableFuture.supplyAsync默认无参有返回值
    //            () -> {
    //              System.out.println("当前线程" + Thread.currentThread().getId());
    //              int i = 10 / 2;
    //              System.out.println("运行结果是" + i);
    //              return i;
    //            },
    //            executors);
    //            .handle( // handle方法相当于whenComplete+exceptionally，既可以捕获异常也可以对异常做处理返回数值
    //                (res, throwable) -> {
    //                  if (res != null) {
    //                    return res;
    //                  }
    //                  System.out.println(throwable.getMessage());
    //                  return -1;
    //                });

    //            .whenComplete( // whenComplete虽然能感知异常但是没法对异常做处理并返回值
    //                (t, u) -> {
    //                  System.out.println("t:--" + t + "-------u:" + u);
    //                })
    //            .exceptionally( // exceptionally对异常做处理并返回值
    //                (throwable) -> {
    //                  return -1;
    //                });
    // 以上总结：handle方法相当于whenComplete+exceptionally

    /**
     * 线程串行化 1、thenRun:不能获取到上一次结果的返回，也不能返回自己的结果 public CompletableFuture<Void> thenRun(Runnable
     * action) 2、thenAccept:能获取到上一次的返回结果，但是不能返回自己的结果public CompletableFuture<Void>
     * thenAccept(Consumer<? super T> action) 3、thenApply:能获取到上一次的返回结果，也能返回自己的结果public <U>
     * CompletableFuture<U> thenApply( Function<? super T,? extends U> fn)
     */
    //    CompletableFuture<String> applyAsync =
    //        CompletableFuture.supplyAsync(
    //                // 使用CompletableFuture.supplyAsync默认无参有返回值
    //                () -> {
    //                  System.out.println("当前线程" + Thread.currentThread().getId());
    //                  int i = 10 / 2;
    //                  System.out.println("运行结果是" + i);
    //                  return i;
    //                },
    //                executors)
    //        .thenRunAsync(
    //            () -> {
    //              System.out.println("任务2执行了");
    //            },
    //            executors)
    //        .thenAcceptAsync(
    //            (res) -> {
    //              System.out.println("任务2执行了,参数是：" + res);
    //            },
    //            executors)
    //         .thenApplyAsync(
    //                (res) -> {
    //                  System.out.println("任务2执行了,参数是：" + res);
    //                  return "Hello" + res;
    //                },
    //                executors);
    //    System.out.println(applyAsync.get());
    //    System.out.println("线程结束运行------------------");

    /**
     * 两个线程组合，都要完成后执行： 1、supplyAsync1.runAfterBothAsync(CompletionStage<?> other, Runnable action,
     * Executor executor)：当前线程和other线程结束后执行action线程，不接收参数无返回值 2、CompletableFuture<Void>
     * thenAcceptBothAsync( CompletionStage<? extends U> other, BiConsumer<? super T, ? super U>
     * action, Executor executor)：当前线程和other线程结束后执行action线程，接收前两个线程参数无返回值 3、<U,V>
     * CompletableFuture<V> thenCombineAsync( CompletionStage<? extends U> other, BiFunction<? super
     * T,? super U,? extends V> fn, Executor executor)：当前线程和other线程结束后执行action线程，接收前两个线程参数有返回值 返回值
     */
    //    CompletableFuture<String> supplyAsync1 =
    //        CompletableFuture.supplyAsync(
    //            // 使用CompletableFuture.supplyAsync默认无参有返回值
    //            () -> {
    //              System.out.println("当前线程1执行了-------");
    //              int i = 10 / 2;
    //              //              try {
    //              //                Thread.sleep(3000);
    //              //              } catch (InterruptedException e) {
    //              //                e.printStackTrace();
    //              //              }
    //              System.out.println("当前线程1结束了-------");
    //              return i + "";
    //            },
    //            executors);
    //    CompletableFuture<String> supplyAsync2 =
    //        CompletableFuture.supplyAsync(
    //            // 使用CompletableFuture.supplyAsync默认无参有返回值
    //            () -> {
    //              System.out.println("当前线程2执行了-------");
    //              try {
    //                Thread.sleep(3000);
    //              } catch (InterruptedException e) {
    //                e.printStackTrace();
    //              }
    //              System.out.println("当前线程2结束了-------");
    //              return "hello";
    //            },
    //            executors);

    //    supplyAsync1.runAfterBothAsync(
    //        supplyAsync2,
    //        () -> {
    //          System.out.println("当前线程3执行了-------");
    //          System.out.println("当前线程3结束了-------");
    //        },
    //        executors);
    //    supplyAsync1.thenAcceptBothAsync(
    //        supplyAsync2,
    //        (s1, s2) -> {
    //          System.out.println("当前线程3执行了-------");
    //          System.out.println("前两次的结果：" + s1 + "->>>>>>" + s2);
    //          System.out.println("当前线程3结束了-------");
    //        },
    //        executors);
    //    CompletableFuture<String> combineAsync =
    //        supplyAsync1.thenCombineAsync(
    //            supplyAsync2,
    //            (s1, s2) -> {
    //              System.out.println("当前线程3执行了-------");
    //              System.out.println("当前线程3结束了-------");
    //              return "dodo" + s1 + s2;
    //            },
    //            executors);
    //    System.out.println(combineAsync.get());

    /**
     * 两个线程组合，任一个完成后执行：(注意两个线程的返回值类型要一致) 1、CompletableFuture<Void>
     * runAfterEitherAsync(CompletionStage<?> other, Runnable action, Executor
     * executor)：当前线程和other线程任意一个结束后执行action线程，不接收参数，无返回值 2、CompletableFuture<Void>
     * acceptEitherAsync( CompletionStage<? extends T> other, Consumer<? super T> action, Executor
     * executor)：当前线程和other线程任意一个结束后执行action线程，接收完成的线程参数，无返回值 3、CompletableFuture<U>
     * applyToEitherAsync( CompletionStage<? extends T> other, Function<? super T, U> fn, Executor
     * executor)：当前线程和other线程任意一个结束后执行action线程，接收完成的线程参数，有返回值
     */

    //    supplyAsync1.runAfterEitherAsync(
    //        supplyAsync2,
    //        () -> {
    //          System.out.println("当前线程3执行了-------");
    //          System.out.println("当前线程3结束了-------");
    //        },
    //        executors);
    //    supplyAsync1.acceptEitherAsync(
    //        supplyAsync2,
    //        res -> {
    //          System.out.println("当前线程3执行了-------");
    //          System.out.println("上次的结果是：" + res);
    //          System.out.println("当前线程3结束了-------");
    //        },
    //        executors);
    //    CompletableFuture<String> applyToEitherAsync =
    //        supplyAsync1.applyToEitherAsync(
    //            supplyAsync2,
    //            res -> {
    //              System.out.println("当前线程3执行了-------");
    //              System.out.println("当前线程3结束了-------");
    //              return "dodo" + res;
    //            },
    //            executors);
    //    System.out.println("返回的结果是:" + applyToEitherAsync.get());

    /** 多任务组合 */
    CompletableFuture<String> imageFuture =
        CompletableFuture.supplyAsync(
            () -> {
              try {
                Thread.sleep(3000);
                System.out.println("查询到商品图片的信息-------");
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
              return "hehe.jpg";
            },
            executors);
    CompletableFuture<String> attrFuture =
        CompletableFuture.supplyAsync(
            () -> {
              try {
                Thread.sleep(5000);
                System.out.println("查询到商品属性的信息-------");
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
              return "256G";
            },
            executors);
    CompletableFuture<String> descFuture =
        CompletableFuture.supplyAsync(
            () -> {
              System.out.println("查询到商品详情的信息-------");
              return "华为";
            },
            executors);
    //    CompletableFuture<Void> allOf = CompletableFuture.allOf(imageFuture, attrFuture,
    // descFuture);
    //    allOf.get(); // 等待三个线程全做完

    CompletableFuture<Object> anyOf = CompletableFuture.anyOf(imageFuture, attrFuture, descFuture);
    anyOf.get(); // 等待三个线程任意一个做完
    System.out.println(anyOf.get());
    System.out.println(
        imageFuture.get()
            + "----------"
            + attrFuture.get()
            + "-----------"
            + descFuture.get()
            + format.format(new Date()));
  }

  public void testThread(String[] args) throws ExecutionException, InterruptedException {
    //
    System.out.println("线程开始运行------------------");

    //    Thread1 thread = new Thread1();  //继承thread类实现
    //    thread.start();

    //    new Thread(new Runnable1()).start(); // 接口实现线程

    //    FutureTask<Integer> task = new FutureTask<>(new Callable1());
    // 使用Callable+FutureTask实现
    //    new Thread(task).start();
    //    Integer i = task.get(); // 阻塞等待线程结束，返回线程运行的结果

    //    FutureTask<Integer> task = new FutureTask<Integer>(new Callable1()); //
    // 使用Runnable+FutureTask实现
    //    new Thread(task).start();
    //    Integer i = task.get(); // 阻塞等待线程结束，返回线程运行的结果

    //    CompletableFuture<Void> future = CompletableFuture.runAsync(new Runnable1(),
    // executors);//使用CompletableFuture.runAsync

    // 普通的juc创建线程池（七大参数）
    // ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor();

    /** 四大常用的线程池 */
    // Executors.newCachedThreadPool(); //核心为0的线程池  所有都可回收 回收快
    // Executors.newFixedThreadPool() //固定线程池大小   一直存活  都不可回收
    // Executors.newScheduledThreadPool() //定时任务的线程池  指定时间后再执行
    // Executors.newSingleThreadExecutor() //单线程的线程池 从后台队列里面一个个获取执行  核心和最大都只有一个

    System.out.println("线程运行结束------------------===");
  }

  public static class Thread1 extends Thread {
    @Override
    public void run() {
      System.out.println("当前线程" + currentThread().getId());
      int i = 10 / 2;
      System.out.println("运行结果是" + i);
    }
  }

  public static class Runnable1 implements Runnable {

    @Override
    public void run() {
      System.out.println("当前线程id是" + Thread.currentThread().getId());
      int i = 10 / 2;
      System.out.println("运行结果是" + i);
    }
  }

  public static class Callable1 implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
      System.out.println("当前线程id是" + Thread.currentThread().getId());
      int i = 10 / 2;
      System.out.println("运行结果是" + i);
      return i;
    }
  }
}
